#!/usr/bin/env python
#引入包
import requests
from requests.auth import HTTPBasicAuth
import json
import unicodedata
from subprocess import Popen, PIPE
import time
import networkx as nx
from sys import exit



<<<<<<<< HEAD:P2Paccelerate.py
#获取回复
========
#获取得到结果
>>>>>>>> 427a200c3601ed58caeb99b314e00e59c661726e:P2P-accelerate.py
def getResponse(url, choice):

    response = requests.get(url, auth=HTTPBasicAuth('admin', 'admin'))

    if (response.ok):
        jData = json.loads(response.content)
        if (choice == "topology"):
            topologyInformation(jData)
        elif (choice == "statistics"):
            getStats(jData)
    else:
        response.raise_for_status()

<<<<<<<< HEAD:P2Paccelerate.py
#获取拓扑图信息
========
#获取拓扑结构信息
>>>>>>>> 427a200c3601ed58caeb99b314e00e59c661726e:P2P-accelerate.py
def topologyInformation(data):
    global switch
    global deviceMAC
    global deviceIP
    global hostPorts
    global linkPorts
    global G
    global cost

    for i in data["network-topology"]["topology"]:

        if "node" in i:
            for j in i["node"]:
               

                if "host-tracker-service:addresses" in j:
                    for k in j["host-tracker-service:addresses"]:
                        ip = k["ip"].encode('ascii', 'ignore')
                        mac = k["mac"].encode('ascii', 'ignore')
                        deviceMAC[ip] = mac
                        deviceIP[mac] = ip

              

                if "host-tracker-service:attachment-points" in j:

                    for k in j["host-tracker-service:attachment-points"]:
                        mac = k["corresponding-tp"].encode('ascii', 'ignore')
                        mac = mac.split(":", 1)[1]
                        ip = deviceIP[mac]
                        temp = k["tp-id"].encode('ascii', 'ignore')
                        switchID = temp.split(":")
                        port = switchID[2]
                        hostPorts[ip] = port
                        switchID = switchID[0] + ":" + switchID[1]
                        switch[ip] = switchID

   
    for i in data["network-topology"]["topology"]:
        if "link" in i:
            for j in i["link"]:
                if "host" not in j['link-id']:
                    src = j["link-id"].encode('ascii', 'ignore').split(":")
                    srcPort = src[2]
                    dst = j["destination"]["dest-tp"].encode(
                        'ascii', 'ignore').split(":")
                    dstPort = dst[2]
                    srcToDst = src[1] + "::" + dst[1]
                    linkPorts[srcToDst] = srcPort + "::" + dstPort
                    G.add_edge((int)(src[1]), (int)(dst[1]))

#获取状态
def getStats(data):
    print ("\nCost Computation....\n")
    global cost
    txRate = 0
    for i in data["node-connector"]:
        tx = int(i["opendaylight-port-statistics:flow-capable-node-connector-statistics"]
                 ["packets"]["transmitted"])
        rx = int(i["opendaylight-port-statistics:flow-capable-node-connector-statistics"]
                 ["packets"]["received"])
        txRate = tx + rx
        

    time.sleep(2)

    response = requests.get(stats, auth=HTTPBasicAuth('admin', 'admin'))
    tempJSON = ""
    if (response.ok):
        tempJSON = json.loads(response.content)

    for i in tempJSON["node-connector"]:
        tx = int(i["opendaylight-port-statistics:flow-capable-node-connector-statistics"]
                 ["packets"]["transmitted"])
        rx = int(i["opendaylight-port-statistics:flow-capable-node-connector-statistics"]
                 ["packets"]["received"])
        cost = cost + tx + rx - txRate

    #cost = cost + txRate
    # print cost

#定义系统控制
def systemCommand(cmd):
    terminalProcess = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
    terminalOutput, stderr = terminalProcess.communicate()
    print("\n*** Flow Pushed\n")

#流量规则
def pushFlowRules(bestPath):

    bestPath = bestPath.split("::")

    for currentNode in range(0, len(bestPath)-1):
        if (currentNode == 0):
            inport = hostPorts[h2]
            srcNode = bestPath[currentNode]
            dstNode = bestPath[currentNode+1]
            outport = linkPorts[srcNode + "::" + dstNode]
            outport = outport[0]
        else:
            prevNode = bestPath[currentNode-1]
            # print prevNode
            srcNode = bestPath[currentNode]
            # print srcNode
            dstNode = bestPath[currentNode+1]
            inport = linkPorts[prevNode + "::" + srcNode]
            inport = inport.split("::")[1]
            outport = linkPorts[srcNode + "::" + dstNode]
            outport = outport.split("::")[0]

        xmlSrcToDst = '\'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><flow xmlns=\"urn:opendaylight:flow:inventory\"><priority>32767</priority><flow-name>Load Balance 1</flow-name><match><in-port>' + \
            str(inport) + '</in-port><ipv4-destination>10.0.0.1/32</ipv4-destination><ipv4-source>10.0.0.4/32</ipv4-source><ethernet-match><ethernet-type><type>2048</type></ethernet-type></ethernet-match></match><id>1</id><table_id>0</table_id><instructions><instruction><order>0</order><apply-actions><action><order>0</order><output-action><output-node-connector>' + \
            str(outport) + '</output-node-connector></output-action></action></apply-actions></instruction></instructions></flow>\''

        xmlDstToSrc = '\'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><flow xmlns=\"urn:opendaylight:flow:inventory\"><priority>32767</priority><flow-name>Load Balance 2</flow-name><match><in-port>' + \
            str(outport) + '</in-port><ipv4-destination>10.0.0.4/32</ipv4-destination><ipv4-source>10.0.0.1/32</ipv4-source><ethernet-match><ethernet-type><type>2048</type></ethernet-type></ethernet-match></match><id>2</id><table_id>0</table_id><instructions><instruction><order>0</order><apply-actions><action><order>0</order><output-action><output-node-connector>' + \
            str(inport) + '</output-node-connector></output-action></action></apply-actions></instruction></instructions></flow>\''

        flowURL = "http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:" + \
            bestPath[currentNode] + "/table/0/flow/1"

        command = 'curl --user "admin":"admin" -H "Accept: application/xml" -H "Content-type: application/xml" -X PUT ' + \
            flowURL + ' -d ' + xmlSrcToDst

        systemCommand(command)

        flowURL = "http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:" + \
            bestPath[currentNode] + "/table/0/flow/2"

        command = 'curl --user "admin":"admin" -H "Accept: application/xml" -H "Content-type: application/xml" -X PUT ' + \
            flowURL + ' -d ' + xmlDstToSrc

        systemCommand(command)

    srcNode = bestPath[-1]
    prevNode = bestPath[-2]
    inport = linkPorts[prevNode + "::" + srcNode]
    inport = inport.split("::")[1]
    outport = hostPorts[h1]

    xmlSrcToDst = '\'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><flow xmlns=\"urn:opendaylight:flow:inventory\"><priority>32767</priority><flow-name>Load Balance 1</flow-name><match><in-port>' + \
        str(inport) + '</in-port><ipv4-destination>10.0.0.1/32</ipv4-destination><ipv4-source>10.0.0.4/32</ipv4-source><ethernet-match><ethernet-type><type>2048</type></ethernet-type></ethernet-match></match><id>1</id><table_id>0</table_id><instructions><instruction><order>0</order><apply-actions><action><order>0</order><output-action><output-node-connector>' + \
        str(outport) + '</output-node-connector></output-action></action></apply-actions></instruction></instructions></flow>\''

    xmlDstToSrc = '\'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><flow xmlns=\"urn:opendaylight:flow:inventory\"><priority>32767</priority><flow-name>Load Balance 2</flow-name><match><in-port>' + \
        str(outport) + '</in-port><ipv4-destination>10.0.0.4/32</ipv4-destination><ipv4-source>10.0.0.1/32</ipv4-source><ethernet-match><ethernet-type><type>2048</type></ethernet-type></ethernet-match></match><id>2</id><table_id>0</table_id><instructions><instruction><order>0</order><apply-actions><action><order>0</order><output-action><output-node-connector>' + \
        str(inport) + '</output-node-connector></output-action></action></apply-actions></instruction></instructions></flow>\''

    flowURL = "http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:" + \
        bestPath[-1] + "/table/0/flow/1"

    command = 'curl --user \"admin\":\"admin\" -H \"Accept: application/xml\" -H \"Content-type: application/xml\" -X PUT ' + \
        flowURL + ' -d ' + xmlSrcToDst

    systemCommand(command)

    flowURL = "http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:" + \
        bestPath[-1] + "/table/0/flow/2"

    command = 'curl --user "admin":"admin" -H "Accept: application/xml" -H "Content-type: application/xml" -X PUT ' + \
        flowURL + ' -d ' + xmlDstToSrc

    systemCommand(command)



global h1, h2, h3

h1 = ""
h2 = ""

print("Enter Host 1'ip address")
h1 = int(input())
print("\nEnter Host 2'ip address")
h2 = int(input())
print("\nEnter Host 3'ip address (switch or H2'neighbor)")
h3 = int(input())
flag = True

while flag:

    # 创建图表
    G = nx.Graph()

    #存储H3和连接H4的交换机的信息
    switch = {}

    # 主机mac
    deviceMAC = {}

    # 主机ip
    deviceIP = {}

    # 存储H3和链接H4的交换机的信息
    switchLinks = {}

    # 存储主机交换机节点
    hostPorts = {}

    # 存储交换机到交换机的链路
    path = {}
    # 存储链路节点
    linkPorts = {}
    # 存储最终链路
    finalLinkTX = {}
    # 存储Port Key
    portKey = ""
    # 统计信息
    global stats
    stats = ""
    # 存储链路cost
    global cost
    cost = 0

    try:
       
        topology = "http://127.0.0.1:8181/restconf/operational/network-topology:network-topology"
        getResponse(topology, "topology")


        print("\nDevice IP & MAC\n")
        print (deviceMAC)


        print ("\nSwitch:Device Mapping\n")
        print (switch)


        print ("\nHost:Port Mapping To Switch\n")
        print (hostPorts)


        print ("\nSwitch:Switch Port:Port Mapping\n")
        print (linkPorts)


        print ("\nAll Paths\n")
     
        for path in nx.all_shortest_paths(G, source=int(switch[h2].split(":", 1)[1]), target=int(switch[h1].split(":", 1)[1]), weight=None):
            print (path)


        tmp = ""
        for currentPath in nx.all_shortest_paths(G, source=int(switch[h2].split(":", 1)[1]), target=int(switch[h1].split(":", 1)[1]), weight=None):
            for node in range(0, len(currentPath)-1):
                tmp = tmp + str(currentPath[node]) + "::"
                key = str(currentPath[node]) + "::" + str(currentPath[node+1])
                port = linkPorts[key]
                port = port.split(":", 1)[0]
                port = int(port)
                stats = "http://localhost:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:" + \
                    str(currentPath[node])+"/node-connector/openflow:" + \
                    str(currentPath[node])+":"+str(port)
                getResponse(stats, "statistics")
            tmp = tmp + str(currentPath[len(currentPath)-1])
            tmp = tmp.strip("::")
            finalLinkTX[tmp] = cost
            cost = 0
            tmp = ""

        print ("\nFinal Link Cost\n")
        print (finalLinkTX)

        shortestPath = min(finalLinkTX, key=finalLinkTX.get)
        print ("\n\nShortest Path: ", shortestPath)

        pushFlowRules(shortestPath)

        time.sleep(60)
    except KeyboardInterrupt:
        break
        exit
